package system

import (
	"MoSkeleton/framework/core/models"
	"MoSkeleton/models/base"
	"errors"
	"gorm.io/gorm"
)

type SysRole struct {
	models.MoModel
	RoleName          string `gorm:"column:role_name;type:VARCHAR(30);NOT NULL"`
	RoleKey           string `gorm:"column:role_key;type:VARCHAR(100);NOT NULL"`
	RoleSort          int32  `gorm:"column:role_sort;type:INT;NOT NULL"`
	DataScope         string `gorm:"column:data_scope;type:CHAR(1);"`
	MenuCheckStrictly bool   `gorm:"column:menu_check_strictly;type:TINYINT(1);"`
	DeptCheckStrictly bool   `gorm:"column:dept_check_strictly;type:TINYINT(1);"`
	Status            string `gorm:"column:status;type:CHAR(1);NOT NULL"`
	DelFlag           string `gorm:"column:del_flag;type:CHAR(1);"`
	CreatedBy         string `gorm:"column:created_by;type:VARCHAR(64);"`
	UpdatedBy         string `gorm:"column:updated_by;type:VARCHAR(32);"`
	Remark            string `gorm:"column:remark;type:VARCHAR(500);"`
}

func (b *SysRole) TableName() string {
	return "sys_role"
}

func (b *SysRole) CheckUniqueName(tx *gorm.DB, roleName string) (bool, error) {
	var count int64
	db := base.GetModelDB(tx).Model(b).Where("role_name = ?", roleName)
	if b.ID > 0 {
		db = db.Where("id <> ?", b.ID)
	}
	err := db.Count(&count).Error
	if err != nil {
		return false, err
	}
	return count == 0, nil
}

func (b *SysRole) CheckUniqueKey(tx *gorm.DB, roleKey string) (bool, error) {
	var count int64
	db := base.GetModelDB(tx).Model(b).Where("role_key = ?", roleKey)
	if b.ID > 0 {
		db = db.Where("id <> ?", b.ID)
	}
	err := db.Count(&count).Error
	return count == 0, err
}

func (b *SysRole) DeleteByRoleIds(tx *gorm.DB, roleIds *[]uint64) (bool, error) {
	err := tx.Where("id in (?)", *roleIds).Delete(b).Error
	if err != nil {
		return false, err
	}
	return true, nil
}

func (b *SysRole) UpdateRoleById(tx *gorm.DB) (int64, error) {
	result := base.GetModelDB(tx).Updates(b)
	return result.RowsAffected, result.Error
}

func (b *SysRole) UpdateStatus(tx *gorm.DB, status string) (bool, error) {
	result := base.GetModelDB(tx).Model(b).Where("id = ?", b.ID).Update("status", status)
	return result.RowsAffected > 0, result.Error
}

func (b *SysRole) IsAdmin() bool {
	return IsRoleAdmin(b.ID)
}

func IsRoleAdmin(id uint64) bool {
	return id == 1
}

func IsRoleIdStrAdmin(id string) bool {
	return id == "1"
}

func (b *SysRole) IdsHasAdmin(ids *[]uint64) bool {
	for _, id := range *ids {
		if IsRoleAdmin(id) {
			return true
		}
	}
	return false
}

/*
	  select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.menu_check_strictly, r.dept_check_strictly,
	            r.status, r.del_flag, r.create_time, r.remark
	        from sys_role r
		        left join sys_user_role ur on ur.role_id = r.role_id
		        left join sys_user u on u.user_id = ur.user_id
		        left join sys_dept d on u.dept_id = d.dept_id

where r.role_id = #{roleId}
*/
func (b *SysRole) GetById(tx *gorm.DB, id uint64) (*SysRole, error) {
	selectFields := "r.id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.menu_check_strictly, r.dept_check_strictly, r.status, r.del_flag, r.created_at, r.remark"
	db := base.GetModelDB(tx).Distinct(selectFields).Table("sys_role r")
	db.Joins("left join sys_user_role ur on ur.role_id = r.id")
	db.Joins("left join sys_user u on u.id = ur.user_id")
	db.Joins("left join sys_dept d on u.dept_id = d.id")
	db.Where("r.id = ?", id)
	role := &SysRole{}
	err := db.First(role).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	return role, err
}
